package com.skaz.bean;

import lombok.Getter;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;

/**
 * Basic {@code Page} implementation.
 *
 * @param <T> the type of which the page consists.
 * @author Oliver Gierke
 * @author Mark Paluch
 */
public class Page<T> implements Serializable {

    private static final long serialVersionUID = 867755909294344406L;

    @Getter
    private int  no;
    @Getter
    private int  size;
    @Getter
    private long total;
    @Getter
    private List<T> content = new ArrayList<>();

    private boolean hasCount;

    public Page(List<T> data, int no, int size, long total) {
        if (no < 1) {
            throw new IllegalArgumentException("参数错误:no < 1");
        }
        if (size == 0) {
            throw new IllegalArgumentException("参数错误:size = 0");
        }
        this.hasCount = size > 0;
        this.no = no;
        this.size = Math.abs(size);
        this.total = total;
        this.content.addAll(data);
    }

    public Page(List<T> data, Page page) {
        this(data, page.getNo(), page.getSize(), page.getTotal());
    }

    public boolean hasCount() {
        return this.hasCount;
    }

    public boolean hasContent() {
        return !content.isEmpty();
    }

    public List<T> getContent() {
        return Collections.unmodifiableList(content);
    }

    public int getContentSize() {
        return this.content.size();
    }

    public Iterator<T> iterator() {
        return content.iterator();
    }

    public long getOffset() {
        return (this.no - 1) * this.size;// fixed no: this.no * this.size
    }

    public int getTotalPages() {
        return getSize() == 0 ? 1 : ((int) Math.ceil((double) total / (double) getSize()));
    }

    public boolean hasPrevious() {
        return (this.no - 1) > 0;// fixed no: this.no > 0
    }

    public boolean hasNext() {
        return (this.no - 1) + 1 < getTotalPages();// fixed no: this.no < getTotalPages();
    }

    public boolean isFirst() {
        return !hasPrevious();
    }

    public boolean isLast() {
        return !hasNext();
    }

    @Override
    public String toString() {
        String contentType = "UNKNOWN";
        List<T> data = getContent();
        if (data.size() > 0) {
            contentType = data.get(0).getClass().getName();
        }
        return String.format("Page %s of %d containing %s instances", getNo() + 1, getTotalPages(), contentType);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof Page<?>)) {
            return false;
        }
        Page<?> that = (Page<?>) obj;
        return this.total == that.total && super.equals(obj);
    }

    @Override
    public int hashCode() {
        int result = 17;
        result += 31 * (int) (total ^ total >>> 32);
        result += 31 * super.hashCode();
        return result;
    }

}
